using UnityEditor;
using UnityEngine;
using System;
using System.Reflection;

[CustomEditor(typeof(IndicatorData), true)]
[CanEditMultipleObjects]
public class IndicatorDataEditor : Editor
{
    private IndicatorType m_LastIndicatorType;
    private bool m_IsInitialized = false;

    private void OnEnable()
    {
        // 初始化时记录当前的 IndicatorType
        if (target != null && target is IndicatorData indicatorData)
        {
            m_LastIndicatorType = indicatorData.IndicatorType;
            m_IsInitialized = true;
        }
    }

    public override void OnInspectorGUI()
    {
        // 检查目标对象是否仍然有效（可能在转换过程中被删除）
        if (target == null)
        {
            return;
        }
        
        serializedObject.Update();
        IndicatorData indicatorData = (IndicatorData)target;

        // 初始化检查
        if (!m_IsInitialized)
        {
            m_LastIndicatorType = indicatorData.IndicatorType;
            m_IsInitialized = true;
        }

        // 检测 IndicatorType 是否改变
        EditorGUI.BeginChangeCheck();
        
        // 显示基础字段
        EditorGUILayout.PropertyField(serializedObject.FindProperty("IndicatorType"));
        EditorGUILayout.PropertyField(serializedObject.FindProperty("Range"));

        // 如果 IndicatorType 改变了，记录并标记需要刷新
        bool indicatorTypeChanged = EditorGUI.EndChangeCheck();
        
        // 获取新的 IndicatorType 值
        IndicatorType newType = indicatorData.IndicatorType;
        IndicatorType oldType = m_LastIndicatorType;
        
        // 检测 IndicatorType 是否改变（包括通过代码修改的情况）
        if (indicatorTypeChanged || oldType != newType)
        {
            // 立即应用修改
            serializedObject.ApplyModifiedProperties();
            
            // 如果类型改变，且资产文件类型不匹配，尝试转换资产文件类型
            if (indicatorTypeChanged && oldType != newType)
            {
                // 保存资产路径和类型，用于延迟回调
                string assetPath = AssetDatabase.GetAssetPath(indicatorData);
                IndicatorType targetType = newType;
                
                // 延迟执行转换，避免在 GUI 绘制过程中修改资产
                EditorApplication.delayCall += () =>
                {
                    // 重新加载资产，因为可能在延迟期间资产已经改变
                    IndicatorData asset = AssetDatabase.LoadAssetAtPath<IndicatorData>(assetPath);
                    if (asset != null)
                    {
                        TryConvertAssetType(asset, targetType);
                    }
                };
            }
            
            m_LastIndicatorType = newType;
            
            // 标记对象为已修改，确保 Unity 保存更改
            EditorUtility.SetDirty(indicatorData);
            // 强制刷新 Inspector
            Repaint();
            // 重新更新 serializedObject
            serializedObject.Update();
        }

        // 根据 IndicatorType 的值显示对应的特有字段
        EditorGUILayout.Space();
        EditorGUILayout.LabelField("类型特有参数", EditorStyles.boldLabel);

        // 根据 IndicatorType 的值来确定要显示的字段（而不是资产文件的实际类型）
        string[] fieldsToShow = null;
        
        switch (indicatorData.IndicatorType)
        {
            case IndicatorType.Sector:
                fieldsToShow = new string[] { "Angle", "Radius", "Quality" };
                break;
            case IndicatorType.OBB:
                fieldsToShow = new string[] { "ObbHalfExtents", "ObbRotationEuler", "ObbFillDirection" };
                break;
            case IndicatorType.Circle:
                fieldsToShow = new string[] { "CircleRadius", "CircleQuality" };
                break;
            case IndicatorType.Rectangle:
                fieldsToShow = new string[] { "RectangleWidth", "RectangleLength" };
                break;
            case IndicatorType.Capsule:
                fieldsToShow = new string[] { "CapsuleRadius", "CapsuleHeight" };
                break;
            case IndicatorType.CapsuleCast:
                fieldsToShow = new string[] { "CapsuleCastRadius", "CapsuleCastHeight", "CapsuleCastRange" };
                break;
            case IndicatorType.Cone:
                fieldsToShow = new string[] { "ConeAngle", "ConeHeight", "ConeQuality" };
                break;
            case IndicatorType.Donut:
                fieldsToShow = new string[] { "DonutInnerRadius", "DonutOuterRadius", "DonutQuality" };
                break;
            case IndicatorType.Cross:
                fieldsToShow = new string[] { "CrossHalfWidth", "CrossMaxLength" };
                break;
            case IndicatorType.SphereCast:
                fieldsToShow = new string[] { "SphereCastRadius", "SphereCastRange" };
                break;
            case IndicatorType.Parabola:
                fieldsToShow = new string[] { "ParabolaProjectileSpeed", "ParabolaImpactRadius", "ParabolaGravity" };
                break;
            case IndicatorType.Pie:
                fieldsToShow = new string[] { "Angle", "Radius", "Quality" };
                break;
            case IndicatorType.Ring:
                fieldsToShow = new string[] { "InnerRadius", "OuterRadius", "Quality" };
                break;
        }

        // 使用 FindProperty 直接查找并显示字段（优先使用这种方式，因为它能立即反映 IndicatorType 的变化）
        bool hasDrawnFields = false;
        if (fieldsToShow != null)
        {
            foreach (string fieldName in fieldsToShow)
            {
                var prop = serializedObject.FindProperty(fieldName);
                if (prop != null)
                {
                    EditorGUILayout.PropertyField(prop, true);
                    hasDrawnFields = true;
                }
            }
        }

        // 如果 FindProperty 找不到字段，尝试使用迭代器遍历所有属性
        if (!hasDrawnFields && fieldsToShow != null)
        {
            SerializedProperty iterator = serializedObject.GetIterator();
            bool enterChildren = true;
            iterator.NextVisible(true);
            
            while (iterator.NextVisible(enterChildren))
            {
                enterChildren = false;

                // 跳过基础字段（已经显示过了）
                if (iterator.name == "m_Script" || 
                    iterator.name == "IndicatorType" || 
                    iterator.name == "Range")
                {
                    continue;
                }

                // 如果当前字段在需要显示的列表中，就显示它
                foreach (string fieldName in fieldsToShow)
                {
                    if (iterator.name == fieldName)
                    {
                        EditorGUILayout.PropertyField(iterator, true);
                        hasDrawnFields = true;
                        break;
                    }
                }
            }
        }

        // 如果没有绘制任何字段，显示提示信息
        if (!hasDrawnFields)
        {
            string expectedTypeName = GetExpectedTypeName(indicatorData.IndicatorType);
            string currentTypeName = indicatorData.GetType().Name;
            
            if (expectedTypeName != currentTypeName)
            {
                EditorGUILayout.HelpBox(
                    $"当前资产文件类型是 {currentTypeName}，但 IndicatorType 设置为 {indicatorData.IndicatorType}。\n" +
                    $"要使用 {indicatorData.IndicatorType} 类型的字段，请将资产文件类型更换为 {expectedTypeName}。",
                    MessageType.Warning);
                
                // 添加转换按钮
                EditorGUILayout.Space();
                if (GUILayout.Button($"转换为 {expectedTypeName}", GUILayout.Height(25)))
                {
                    // 保存资产路径，因为转换后旧对象会被删除
                    string assetPath = AssetDatabase.GetAssetPath(indicatorData);
                    IndicatorType targetType = indicatorData.IndicatorType;
                    
                    // 延迟执行转换，避免在 GUI 绘制过程中修改资产
                    EditorApplication.delayCall += () =>
                    {
                        // 重新加载资产
                        IndicatorData asset = AssetDatabase.LoadAssetAtPath<IndicatorData>(assetPath);
                        if (asset != null)
                        {
                            TryConvertAssetType(asset, targetType);
                        }
                    };
                }
            }
            else
            {
                EditorGUILayout.HelpBox(
                    $"当前类型 {indicatorData.IndicatorType} 没有找到对应的特有字段。",
                    MessageType.Info);
            }
        }

        if (serializedObject.ApplyModifiedProperties())
        {
            EditorUtility.SetDirty(indicatorData);
        }
    }

    /// <summary>
    /// 根据 IndicatorType 获取期望的资产文件类型名称
    /// </summary>
    private string GetExpectedTypeName(IndicatorType type)
    {
        switch (type)
        {
            case IndicatorType.Sector:
                return "SectorIndicatorData";
            case IndicatorType.OBB:
                return "OBBIndicatorData";
            case IndicatorType.Circle:
                return "CirlcleIndicatorData";
            case IndicatorType.Rectangle:
                return "RectangleIndicatorData";
            case IndicatorType.Capsule:
                return "CapsuleIndicatorData";
            case IndicatorType.CapsuleCast:
                return "CapsuleCastIndicatorData";
            case IndicatorType.Cone:
                return "ConeIndicatorData";
            case IndicatorType.Donut:
                return "DonutIndicatorData";
            case IndicatorType.Cross:
                return "CrossIndicatorData";
            case IndicatorType.SphereCast:
                return "SphereCastIndicatorData";
            case IndicatorType.Parabola:
                return "ParabolaIndicatorData";
            case IndicatorType.Pie:
                return "PieIndicatorData";
            case IndicatorType.Ring:
                return "RingIndicatorData";
            default:
                return "IndicatorData";
        }
    }

    /// <summary>
    /// 根据 IndicatorType 获取对应的类型
    /// </summary>
    private Type GetExpectedType(IndicatorType type)
    {
        string typeName = GetExpectedTypeName(type);
        string fullTypeName = $"UnityEngine.{typeName}";
        
        // 尝试在当前程序集中查找类型
        Type foundType = Type.GetType(fullTypeName);
        if (foundType == null)
        {
            // 尝试在所有已加载的程序集中查找
            foreach (var assembly in System.AppDomain.CurrentDomain.GetAssemblies())
            {
                foundType = assembly.GetType(typeName);
                if (foundType != null) break;
            }
        }
        
        return foundType;
    }

    /// <summary>
    /// 尝试转换资产文件类型
    /// </summary>
    private void TryConvertAssetType(IndicatorData currentAsset, IndicatorType newType)
    {
        string expectedTypeName = GetExpectedTypeName(newType);
        string currentTypeName = currentAsset.GetType().Name;
        
        // 如果类型已经匹配，不需要转换
        if (expectedTypeName == currentTypeName)
        {
            return;
        }
        
        // 获取期望的类型
        Type expectedType = GetExpectedType(newType);
        if (expectedType == null)
        {
            Debug.LogWarning($"无法找到类型: {expectedTypeName}");
            return;
        }
        
        // 获取资产文件路径
        string assetPath = AssetDatabase.GetAssetPath(currentAsset);
        if (string.IsNullOrEmpty(assetPath))
        {
            Debug.LogWarning("无法获取资产文件路径");
            return;
        }
        
        // 询问用户是否要转换
        if (!EditorUtility.DisplayDialog(
            "转换资产文件类型",
            $"当前资产文件类型是 {currentTypeName}，但 IndicatorType 设置为 {newType}。\n\n" +
            $"是否要将资产文件类型转换为 {expectedTypeName}？\n\n" +
            $"注意：此操作会创建新的资产文件并删除旧文件。",
            "转换", "取消"))
        {
            return;
        }
        
        // 保存当前的基础字段值
        float range = currentAsset.Range;
        IndicatorType indicatorType = currentAsset.IndicatorType;
        string assetName = currentAsset.name;
        
        // 获取旧资产的 GUID（用于查找引用）
        string oldGUID = AssetDatabase.AssetPathToGUID(assetPath);
        
        // 创建临时路径用于新资产
        string tempPath = assetPath.Replace(".asset", "_temp.asset");
        
        // 创建新类型的实例
        ScriptableObject newAsset = ScriptableObject.CreateInstance(expectedType);
        if (newAsset == null)
        {
            Debug.LogError($"无法创建 {expectedTypeName} 实例");
            return;
        }
        
        // 复制基础字段
        if (newAsset is IndicatorData newIndicatorData)
        {
            newIndicatorData.Range = range;
            newIndicatorData.IndicatorType = indicatorType;
        }
        
        // 复制名称
        newAsset.name = assetName;
        
        // 先创建新资产到临时路径
        AssetDatabase.CreateAsset(newAsset, tempPath);
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
        
        // 获取新资产的 GUID
        string newGUID = AssetDatabase.AssetPathToGUID(tempPath);
        
        // 更新所有引用
        int replacedCount = ReplaceAllReferences(oldGUID, newGUID, assetPath, tempPath);
        
        // 删除旧资产文件
        AssetDatabase.DeleteAsset(assetPath);
        
        // 将新资产移动到原路径
        string moveError = AssetDatabase.MoveAsset(tempPath, assetPath);
        if (!string.IsNullOrEmpty(moveError))
        {
            Debug.LogError($"移动资产文件失败: {moveError}");
            return;
        }
        
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
        
        // 重新加载新资产并选中
        IndicatorData loadedAsset = AssetDatabase.LoadAssetAtPath<IndicatorData>(assetPath);
        if (loadedAsset != null)
        {
            Selection.activeObject = loadedAsset;
            EditorUtility.FocusProjectWindow();
            // 强制刷新 Inspector
            EditorUtility.SetDirty(loadedAsset);
        }
        
        Debug.Log($"已将资产文件 {assetPath} 从 {currentTypeName} 转换为 {expectedTypeName}，并更新了 {replacedCount} 个引用");
    }

    /// <summary>
    /// 替换所有对旧资产的引用
    /// </summary>
    private int ReplaceAllReferences(string oldGUID, string newGUID, string oldPath, string newPath)
    {
        int replacedCount = 0;
        
        // 使用 FindAssets 查找可能包含引用的资产类型
        // 查找所有 ScriptableObject 资产
        string[] scriptableObjectGuids = AssetDatabase.FindAssets("t:ScriptableObject");
        // 查找所有预制体
        string[] prefabGuids = AssetDatabase.FindAssets("t:GameObject");
        // 查找所有场景
        string[] sceneGuids = AssetDatabase.FindAssets("t:Scene");
        
        // 合并所有 GUID
        System.Collections.Generic.HashSet<string> allGuids = new System.Collections.Generic.HashSet<string>();
        foreach (string guid in scriptableObjectGuids) allGuids.Add(guid);
        foreach (string guid in prefabGuids) allGuids.Add(guid);
        foreach (string guid in sceneGuids) allGuids.Add(guid);
        
        int totalAssets = allGuids.Count;
        int processedAssets = 0;
        
        UnityEngine.Object newAsset = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(newPath);
        if (newAsset == null)
        {
            Debug.LogError($"无法加载新资产: {newPath}");
            return 0;
        }
        
        foreach (string guid in allGuids)
        {
            string assetPath = AssetDatabase.GUIDToAssetPath(guid);
            
            // 跳过旧资产和新资产本身
            if (assetPath == oldPath || assetPath == newPath)
            {
                continue;
            }
            
            try
            {
                // 尝试加载资产
                UnityEngine.Object asset = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(assetPath);
                if (asset == null)
                {
                    continue;
                }
                
                // 使用 SerializedObject 来查找和替换引用
                SerializedObject serializedObject = new SerializedObject(asset);
                bool hasChanges = false;
                
                // 遍历所有属性，查找对象引用
                SerializedProperty iterator = serializedObject.GetIterator();
                bool enterChildren = true;
                
                while (iterator.Next(enterChildren))
                {
                    enterChildren = false;
                    
                    // 只处理对象引用属性
                    if (iterator.propertyType == SerializedPropertyType.ObjectReference)
                    {
                        if (iterator.objectReferenceValue != null)
                        {
                            string refPath = AssetDatabase.GetAssetPath(iterator.objectReferenceValue);
                            if (refPath == oldPath)
                            {
                                iterator.objectReferenceValue = newAsset;
                                hasChanges = true;
                                replacedCount++;
                            }
                        }
                    }
                    // 如果是数组或嵌套对象，需要进入子属性
                    else if (iterator.hasChildren && 
                             (iterator.isArray || iterator.propertyType == SerializedPropertyType.Generic))
                    {
                        enterChildren = true;
                    }
                }
                
                if (hasChanges)
                {
                    serializedObject.ApplyModifiedPropertiesWithoutUndo();
                    EditorUtility.SetDirty(asset);
                }
            }
            catch (System.Exception e)
            {
                Debug.LogWarning($"处理资产 {assetPath} 时出错: {e.Message}");
            }
            
            processedAssets++;
            // 每处理50个资产显示一次进度
            if (processedAssets % 50 == 0)
            {
                float progress = (float)processedAssets / totalAssets;
                EditorUtility.DisplayProgressBar("更新引用", $"正在处理资产... ({processedAssets}/{totalAssets})", progress);
            }
        }
        
        EditorUtility.ClearProgressBar();
        
        return replacedCount;
    }

}

